﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Facebook;

namespace FeedBack {
    public class StoryProcessor {

        public event EventHandler<VideoInProgressUpdatedEventArgs> VideoInProgressUpdated;

        public int StoryInProgress { get; private set; }


        public void Process(JsonObject json) {
            //"message": "CCTVB!!!",
            //"story": "PassionTimes 熱血時報 shared 自由市場's photo.",
            //"picture": "https://fbcdn-sphotos-c-a.akamaihd.net/hphotos-ak-xpa1/v/t1.0-9/s130x130/10393995_267713170019034_1415758717313800447_n.jpg?oh=930373322eb7f662e753ddb188e41376&oe=54C7E050&__gda__=1421176502_33d059b194f0faf3404a7f4f0961646d",
            //"link": "https://www.facebook.com/117904764999876/photos/a.118177608305925.2126.117904764999876/267713170019034/?type=1",
            //"source": "https://fbcdn-video-e-a.akamaihd.net/hvideo-ak-xfp1/v/t42.1790-2/10290074_10154675843900788_363278391_n.mp4?oh=4fef9727aac3bbf3f112e78c3e2ec79f&oe=54337476&__gda__=1412666349_03edc4cc0b994711d74c454162086df9",
            //"caption": "pic.twitter.com",
            //"description": "Get the whole picture - and other photos from Richard Lo", 

            Story story = new Story(json);
            Debug.WriteLine(string.Format("type: {0}", story.Type));
            Debug.WriteLine(string.Format("message: {0}", story.Message));
            Debug.WriteLine(string.Format("link: {0}", story.Link));
            Debug.WriteLine(string.Format("source: {0}", story.Source));
            Debug.WriteLine(string.Format("updated_time: {0}", story.Json["updated_time"]));
            Debug.WriteLine("-------------------------------");

            if (DateTime.Parse(story.Json["created_time"] as string) <= Configuration.ProcessFileUntil) {
                if (Configuration.DownloadVideo && (story.Type == "video" ||
                    ((story.Type == "link" && story.Link != null) &&
                     (story.Link.DnsSafeHost.Contains("youtube.com") ||
                      story.Link.DnsSafeHost.Contains("youtu.be"))))) {
                    var downloaderFactory = new DownloaderFactory();
                    var downloader = downloaderFactory.Create(story);
                    Download(story, downloader);
                }
                else if ((Configuration.DownloadLink && story.Type == "link") ||
                         (Configuration.DownloadPhoto && story.Type == "photo")) {
                    var downloader = new DefaultLinkDownloader();
                    Download(story, downloader);
                }
                else if ((Configuration.DownloadStatus && story.Type == "status")) {
                    var downloader = new DefaultStatusDownloader();
                    Download(story, downloader);
                }
            }
        }

        private void Download(Story story, IDownloader downloader) {
            var filename = downloader.CandidateFileName(story);

            if (filename != null) {
                var dir = StoryDirectory(story);
                var storyFilename = Path.Combine(dir, Path.GetFileNameWithoutExtension(filename) + ".json");

                var temp = Path.GetFileNameWithoutExtension(filename);
                if (!File.Exists(storyFilename) && temp.Length > 40) {
                    temp = temp.Substring(0, temp.Length - 20);
                    var tempDir = Path.GetDirectoryName(storyFilename);
                    if (Directory.Exists(tempDir) && Directory.GetFiles(tempDir, temp + "*.*").Any() && !Configuration.Overwrite) {
                        return;
                    }
                }

                if (!File.Exists(storyFilename) || Configuration.Overwrite) {
                    if (File.Exists(storyFilename) &&
                        DateTime.UtcNow.Subtract(File.GetLastWriteTimeUtc(storyFilename)).TotalHours < 2) {
                        return;
                    }

                    downloader.Completed += downloader_Completed;

                    StoryInProgress++;
                    OnVideoInProgressUpdated();
                    downloader.Download(story);
                }
            }
        }


        private void OnVideoInProgressUpdated() {
            if (VideoInProgressUpdated != null) {
                VideoInProgressUpdated(this, new VideoInProgressUpdatedEventArgs { Count = StoryInProgress });
            }
        }


        void downloader_Completed(object sender, StoryDownloadedEventArgs e) {
            StoryInProgress--;
            OnVideoInProgressUpdated();

            if (e.Success) {
                var story = e.Story;

                var dir = StoryDirectory(story);
                dir.EnsureDirectory();
                var creationTime = DateTime.Parse(story.Json["created_time"] as string);

                for (int i = 0; i < 3; i++) {
                    try {
                        var storyFilename = Path.GetFileNameWithoutExtension(e.Filename) + ".json";
                        if (File.Exists(Path.Combine(dir, storyFilename)) && Configuration.Overwrite) {
                            foreach (var file in Directory.GetFiles(dir, Path.GetFileNameWithoutExtension(e.Filename) + ".*")) {
                                File.Delete(file);
                            }
                        }

                        File.SetCreationTimeUtc(e.Filename, creationTime);
                        File.Move(e.Filename, Path.Combine(dir, Path.GetFileName(e.Filename)));
                        IDownloader downloader = sender as IDownloader;
                        downloader.PostProcess(dir, story);
                        story.Json["backup"] = Path.GetFileName(e.Filename);
                        var filename = Path.Combine(dir, storyFilename);
                        File.WriteAllText(filename, story.Json.ToString());
                        File.SetCreationTimeUtc(filename, creationTime);
                        break;
                    }
                    catch {
                        Thread.Sleep(10000);
                    }
                }
            }
        }

        private static string StoryDirectory(Story story) {

            DateTime date = DateTime.Parse(story.Json["created_time"] as string).ToLocalTime();
            Uri uri = story.Source;
            if (uri == null) {
                uri = story.Link;
            }
            if (uri != null && 
                (uri.DnsSafeHost.Contains("youtube.com") ||
                 uri.DnsSafeHost.Contains("youtu.be"))) {
                return Path.Combine(Configuration.BackupFolder, date.ToString("yyyyMMdd"), uri.DnsSafeHost);
            }
            else {
                var from = story.Json.Get("from")["name"].ToString();

                JsonObject by = null;
                if (story.Json.Keys.Contains("properties")) {
                    // by = story.Json.GetArray("properties").FirstOrDefault(o => o.Keys.Contains("name") && o["name"].Equals("By"));
                }
                var storyTags = story.Json.Get("story_tags");
                string author = null;
                if (storyTags != null) {
                    var key = storyTags.Keys.First();
                    if (storyTags.Keys.Count > 1) {
                        key = storyTags.Keys.First(o => o != "0");
                    }
                    author = storyTags.GetArray(key).First()["name"].ToString();
                }
                else if (by != null) {
                    author = by["text"] as string;
                }
                else {
                    author = from;
                }
                var dir = Path.Combine(Configuration.BackupFolder, date.ToString("yyyyMMdd"), author.RemoveIllegalPathCharacters());
                return dir;
            }
        }
    }
}
